<template>
  <div class="terminal-container">
    <!-- 左侧服务器列表 -->
    <div class="server-list" :class="{ collapsed: isServerListCollapsed }">
      <div class="server-list-header">
        <div class="server-list-title" v-show="!isServerListCollapsed">
          <el-icon><Monitor /></el-icon>
          <span>服务器列表</span>
        </div>
        <div class="server-list-controls">
          <el-button type="primary" size="small" @click="refreshServerList" v-show="!isServerListCollapsed">
            <el-icon><Refresh /></el-icon>
          </el-button>
          <el-button type="info" size="small" @click="toggleServerListCollapse" class="collapse-btn">
            <el-icon v-if="isServerListCollapsed"><DArrowRight /></el-icon>
            <el-icon v-else><DArrowLeft /></el-icon>
          </el-button>
        </div>
      </div>
      
      <div class="server-list-content" v-show="!isServerListCollapsed">
        <div 
          v-for="server in serverList" 
          :key="server.id"
          class="server-item"
          @contextmenu.prevent="showContextMenu($event, server)"
        >
          <div class="server-info">
            <div class="server-name">{{ server.name }}</div>
            <div class="server-ip">{{ server.meta?.ip || 'N/A' }}</div>
            <div class="server-desc">{{ server.description || '无描述' }}</div>
          </div>
          <div class="server-status" :class="{ connected: isServerConnected(server.id) }">
            <el-icon v-if="isServerConnected(server.id)"><Connection /></el-icon>
            <el-icon v-else><Connection /></el-icon>
          </div>
        </div>
        
        <div v-if="serverList.length === 0" class="empty-servers">
          <el-empty description="暂无服务器" />
        </div>
      </div>
    </div>
    
    <!-- 右侧终端区域 -->
    <div class="terminal-area">
      <div class="terminal-header">
        <el-tabs 
          v-model="activeTerminal" 
          type="card" 
          closable 
          @tab-remove="closeTerminal"
          class="terminal-tabs"
        >
          <el-tab-pane 
            v-for="terminal in terminals" 
            :key="terminal.id"
            :label="terminal.name"
            :name="terminal.id"
          >
            <div class="terminal-wrapper">
              <div :ref="el => setTerminalRef(terminal.id, el)" class="terminal"></div>
            </div>
          </el-tab-pane>
        </el-tabs>
        
        <div v-if="terminals.length === 0" class="empty-terminal">
          <el-empty description="请右键选择服务器连接" />
        </div>
      </div>
    </div>
    
    <!-- 右键菜单 -->
    <div 
      v-show="contextMenu.visible" 
      :style="{ left: contextMenu.x + 'px', top: contextMenu.y + 'px' }"
      class="context-menu"
      @click="hideContextMenu"
    >
      <div class="context-menu-title">选择连接账号</div>
      <div 
        v-for="credential in contextMenu.credentials" 
        :key="credential.value"
        class="context-menu-item"
        @click="connectToServer(contextMenu.server, credential)"
      >
        {{ credential.label }}
      </div>
    </div>
    
    <!-- 遮罩层 -->
    <div 
      v-show="contextMenu.visible" 
      class="context-menu-overlay"
      @click="hideContextMenu"
    ></div>
  </div>
</template>

<script setup lang="ts" name="terminalConnect">
import { ref, onMounted, onUnmounted, onActivated, onDeactivated, nextTick, reactive } from 'vue'
import { Terminal } from '@xterm/xterm'
import { FitAddon } from '@xterm/addon-fit'
import { WebLinksAddon } from '@xterm/addon-web-links'
import { ElMessage } from 'element-plus'
import { Monitor, Refresh, Connection, DArrowRight, DArrowLeft } from '@element-plus/icons-vue'
import { Session } from '/@/utils/storage'
import { resourceApi } from '/@/api/resource'
import Constants from '/@/constant/constants'
import '@xterm/xterm/css/xterm.css'

// 响应式数据
const serverList = ref([])
const terminals = ref([])
const activeTerminal = ref('')
const terminalRefs = ref(new Map())

// 右键菜单
const contextMenu = reactive({
  visible: false,
  x: 0,
  y: 0,
  server: null,
  credentials: []
})

// 服务器列表收缩状态
const isServerListCollapsed = ref(false)

// 终端实例映射
const terminalInstances = new Map()
const websocketConnections = new Map()

// 设置终端引用
const setTerminalRef = (terminalId: string, el: HTMLElement) => {
  if (el) {
    terminalRefs.value.set(terminalId, el)
    nextTick(() => {
      initTerminal(terminalId)
    })
  }
}

// 初始化终端
const initTerminal = (terminalId: string) => {
  const terminalEl = terminalRefs.value.get(terminalId)
  if (!terminalEl || terminalInstances.has(terminalId)) return

  // 创建终端实例
  const terminal = new Terminal({
    cursorBlink: true,
    cursorStyle: 'block',
    fontSize: 14,
    fontFamily: 'Consolas, "Courier New", monospace',
    theme: {
      background: '#1e1e1e',
      foreground: '#ffffff',
      cursor: '#ffffff',
      selection: '#3a3a3a'
    },
    allowTransparency: false,
    convertEol: true
  })

  // 创建插件
  const fitAddon = new FitAddon()
  const webLinksAddon = new WebLinksAddon()

  // 加载插件
  terminal.loadAddon(fitAddon)
  terminal.loadAddon(webLinksAddon)

  // 打开终端
  terminal.open(terminalEl)

  // 适配大小
  fitAddon.fit()

  // 监听终端输入
  terminal.onData((data) => {
    const websocket = websocketConnections.get(terminalId)
    if (websocket && websocket.readyState === WebSocket.OPEN) {
      websocket.send(JSON.stringify({
        type: 'input',
        data: data
      }))
    }
  })

  // 保存终端实例和插件
  terminalInstances.set(terminalId, { terminal, fitAddon })

  // 显示欢迎信息
  terminal.writeln('\x1b[1;32m终端已初始化\x1b[0m')
  terminal.writeln('\x1b[33m等待连接服务器...\x1b[0m')
  terminal.writeln('')
}

// 获取服务器列表
const getServerList = async () => {
  try {
    const res = await resourceApi().pageResource({
      type: Constants.RESOURCE_TYPE.SERVER,
      page: 1,
      size: 1000
    })
    serverList.value = res.data.records || []
  } catch (error) {
    console.error('获取服务器列表失败:', error)
    ElMessage.error('获取服务器列表失败')
  }
}

// 刷新服务器列表
const refreshServerList = () => {
  getServerList()
}

// 检查服务器是否已连接
const isServerConnected = (serverId: string) => {
  return terminals.value.some(t => t.serverId === serverId && t.connected)
}

// 显示右键菜单
const showContextMenu = async (event: MouseEvent, server: any) => {
  try {
    // 获取凭据选项
    const res = await resourceApi().getOptions({ 
      types: [Constants.RESOURCE_TYPE.CREDENTIAL] 
    })
    
    contextMenu.credentials = res.data[Constants.RESOURCE_TYPE.CREDENTIAL] || []
    contextMenu.server = server
    contextMenu.x = event.clientX
    contextMenu.y = event.clientY
    contextMenu.visible = true
  } catch (error) {
    console.error('获取凭据列表失败:', error)
    ElMessage.error('获取凭据列表失败')
  }
}

// 隐藏右键菜单
const hideContextMenu = () => {
  contextMenu.visible = false
}

// 切换服务器列表收缩状态
const toggleServerListCollapse = () => {
  isServerListCollapsed.value = !isServerListCollapsed.value
  
  // 延迟重新适配终端大小，等待CSS过渡完成
  setTimeout(() => {
    terminalInstances.forEach((instance, terminalId) => {
      if (instance.fitAddon && instance.terminal) {
        try {
          // 强制刷新终端布局
          instance.terminal.refresh(0, instance.terminal.rows - 1)
          instance.fitAddon.fit()
          
          // 向后端发送终端大小变化消息
          if (instance.websocket && instance.websocket.readyState === WebSocket.OPEN) {
            instance.websocket.send(JSON.stringify({
              type: 'resize',
              terminalSize: {
                cols: instance.terminal.cols,
                rows: instance.terminal.rows
              }
            }))
          }
          
          // 再次刷新确保显示正确
          setTimeout(() => {
            instance.terminal.refresh(0, instance.terminal.rows - 1)
          }, 50)
        } catch (error) {
          console.warn('终端大小适配失败:', error)
        }
      }
    })
  }, 350) // 稍微大于CSS过渡时间(300ms)
}

// 连接到服务器
const connectToServer = async (server: any, credential: any) => {
  hideContextMenu()
  
  const terminalId = `${server.id}_${credential.value}_${Date.now()}`
  const terminalName = `${server.name}@${credential.label}`
  
  // 创建新的终端标签
  const newTerminal = {
    id: terminalId,
    name: terminalName,
    serverId: server.id,
    credentialId: credential.value,
    connected: false,
    server: server,
    credential: credential
  }
  
  terminals.value.push(newTerminal)
  activeTerminal.value = terminalId
  
  // 等待终端初始化完成后再连接
  nextTick(() => {
    setTimeout(() => {
      handleConnect(terminalId, server, credential)
    }, 100)
  })
}

// 处理连接
const handleConnect = async (terminalId: string, server: any, credential: any) => {
  try {
    // 获取用户token
    const token = Session.get('token')
    if (!token) {
      ElMessage.error('用户未登录，请先登录')
      return
    }

    // 创建WebSocket连接
    const wsUrl = `ws://localhost:8080/terminal/ssh?token=${encodeURIComponent(token)}`
    const websocket = new WebSocket(wsUrl)
    
    websocketConnections.set(terminalId, websocket)
    
    const terminalInstance = terminalInstances.get(terminalId)
    if (!terminalInstance) {
      ElMessage.error('终端实例未找到')
      return
    }

    websocket.onopen = () => {
      console.log('WebSocket连接已建立')
      
      // 发送SSH连接配置
      websocket.send(JSON.stringify({
        type: 'connect',
        config: {
          host: server.meta?.ip || server.name,
          port: server.meta?.port || 22,
          serverId: server.id,
          credentialId: credential.value,
        },
        terminalSize: {
          cols: terminalInstance.terminal.cols || 80,
          rows: terminalInstance.terminal.rows || 24
        }
      }))
    }

    websocket.onmessage = (event) => {
      try {
        const message = JSON.parse(event.data)
        
        switch (message.type) {
          case 'connected':
            // 更新终端连接状态
            const terminal = terminals.value.find(t => t.id === terminalId)
            if (terminal) {
              terminal.connected = true
            }
            ElMessage.success(`${server.name} 连接成功`)
            terminalInstance.terminal.clear()
            break
            
          case 'data':
            // 接收到服务器数据，写入终端
            terminalInstance.terminal.write(message.data)
            break
            
          case 'error':
            terminalInstance.terminal.writeln(`\r\n\x1b[31m连接错误: ${message.message}\x1b[0m`)
            ElMessage.error(`连接错误: ${message.message}`)
            break
            
          case 'disconnected':
            // 更新终端连接状态
            const disconnectedTerminal = terminals.value.find(t => t.id === terminalId)
            if (disconnectedTerminal) {
              disconnectedTerminal.connected = false
            }
            ElMessage.warning('SSH连接已断开')
            terminalInstance.terminal.writeln('\r\n\x1b[31m连接已断开\x1b[0m')
            break
        }
      } catch (error) {
        console.error('解析WebSocket消息失败:', error)
      }
    }

    websocket.onerror = (error) => {
      console.error('WebSocket错误:', error)
      ElMessage.error('WebSocket连接失败')
    }

    websocket.onclose = () => {
      console.log('WebSocket连接已关闭')
      // 更新终端连接状态
      const closedTerminal = terminals.value.find(t => t.id === terminalId)
      if (closedTerminal) {
        closedTerminal.connected = false
      }
    }

  } catch (error) {
    console.error('连接失败:', error)
    ElMessage.error('连接失败')
  }
}

// 关闭终端
const closeTerminal = (terminalId: string) => {
  // 断开WebSocket连接
  const websocket = websocketConnections.get(terminalId)
  if (websocket) {
    websocket.send(JSON.stringify({ type: 'disconnect' }))
    websocket.close()
    websocketConnections.delete(terminalId)
  }
  
  // 销毁终端实例
  const terminalInstance = terminalInstances.get(terminalId)
  if (terminalInstance) {
    terminalInstance.terminal.dispose()
    terminalInstances.delete(terminalId)
  }
  
  // 移除终端引用
  terminalRefs.value.delete(terminalId)
  
  // 从终端列表中移除
  const index = terminals.value.findIndex(t => t.id === terminalId)
  if (index > -1) {
    terminals.value.splice(index, 1)
  }
  
  // 如果关闭的是当前活动终端，切换到其他终端
  if (activeTerminal.value === terminalId && terminals.value.length > 0) {
    activeTerminal.value = terminals.value[0].id
  } else if (terminals.value.length === 0) {
    activeTerminal.value = ''
  }
}

// 处理窗口大小变化
const handleResize = () => {
  // 延迟执行，避免频繁调用
  setTimeout(() => {
    terminalInstances.forEach((instance, terminalId) => {
      if (instance.fitAddon && instance.terminal) {
        try {
          instance.fitAddon.fit()
          
          // 向后端发送终端大小变化消息
          if (instance.websocket && instance.websocket.readyState === WebSocket.OPEN) {
            instance.websocket.send(JSON.stringify({
              type: 'resize',
              terminalSize: {
                cols: instance.terminal.cols,
                rows: instance.terminal.rows
              }
            }))
          }
        } catch (error) {
          console.warn('终端大小适配失败:', error)
        }
      }
    })
  }, 100)
}

// 组件挂载
onMounted(() => {
  getServerList()
  
  // 监听点击事件，用于隐藏右键菜单
  document.addEventListener('click', hideContextMenu)
  
  // 监听窗口大小变化
  window.addEventListener('resize', handleResize)
})

// keep-alive 激活时
onActivated(() => {
  console.log('终端页面被激活')
  
  // 重新适配所有终端大小
  nextTick(() => {
    terminalInstances.forEach((instance, terminalId) => {
      if (instance.fitAddon && instance.terminal) {
        try {
          instance.fitAddon.fit()
          
          // 向后端发送终端大小变化消息
          if (instance.websocket && instance.websocket.readyState === WebSocket.OPEN) {
            instance.websocket.send(JSON.stringify({
              type: 'resize',
              terminalSize: {
                cols: instance.terminal.cols,
                rows: instance.terminal.rows
              }
            }))
          }
        } catch (error) {
          console.warn('终端大小适配失败:', error)
        }
      }
    })
  })
})

// keep-alive 停用时
onDeactivated(() => {
  console.log('终端页面被停用')
  // 隐藏右键菜单
  hideContextMenu()
})

// 组件卸载
onUnmounted(() => {
  // 清理所有WebSocket连接
  websocketConnections.forEach((websocket) => {
    if (websocket) {
      websocket.close()
    }
  })
  websocketConnections.clear()
  
  // 清理所有终端实例
  terminalInstances.forEach((instance) => {
    if (instance.terminal) {
      instance.terminal.dispose()
    }
  })
  terminalInstances.clear()
  
  // 移除事件监听
  document.removeEventListener('click', hideContextMenu)
  window.removeEventListener('resize', handleResize)
})
</script>

<style scoped>
.terminal-container {
  display: flex;
  height: calc(100vh - 85px);
  background: #1e1e1e;
  min-width: 800px;
  overflow-x: auto;
}

/* 左侧服务器列表 */
.server-list {
  width: 300px;
  min-width: 300px;
  max-width: 300px;
  background: #2d2d2d;
  border-right: 1px solid #404040;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  transition: all 0.3s ease;
}

.server-list.collapsed {
  width: 50px;
  min-width: 50px;
  max-width: 50px;
}

.server-list-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 15px;
  background: #363636;
  border-bottom: 1px solid #404040;
}

.server-list-controls {
  display: flex;
  gap: 8px;
  align-items: center;
}

.collapse-btn {
  min-width: 32px;
  padding: 6px 8px;
}

.server-list-title {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #ffffff;
  font-weight: 500;
  font-size: 14px;
}

.server-list-content {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
}

.server-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px;
  margin-bottom: 8px;
  background: #363636;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
}

.server-item:hover {
  background: #404040;
  transform: translateY(-1px);
}

.server-info {
  flex: 1;
}

.server-name {
  color: #ffffff;
  font-weight: 500;
  font-size: 14px;
  margin-bottom: 4px;
}

.server-ip {
  color: #4caf50;
  font-family: monospace;
  font-size: 12px;
  margin-bottom: 2px;
}

.server-desc {
  color: #cccccc;
  font-size: 11px;
  opacity: 0.8;
}

.server-status {
  color: #f44336;
  transition: color 0.2s;
}

.server-status.connected {
  color: #4caf50;
}

.empty-servers {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 200px;
}

/* 右侧终端区域 */
.terminal-area {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.terminal-header {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.terminal-tabs {
  flex: 1;
}

.terminal-wrapper {
  height: 100%;
  padding: 10px;
  overflow: hidden;
}

.terminal {
  width: 100%;
  height: 100%;
}

.empty-terminal {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}

/* 右键菜单 */
.context-menu {
  position: fixed;
  background: #2d2d2d;
  border: 1px solid #404040;
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  z-index: 9999;
  min-width: 150px;
  overflow: hidden;
}

.context-menu-title {
  padding: 8px 12px;
  background: #363636;
  color: #ffffff;
  font-size: 12px;
  font-weight: 500;
  border-bottom: 1px solid #404040;
}

.context-menu-item {
  padding: 8px 12px;
  color: #cccccc;
  cursor: pointer;
  font-size: 13px;
  transition: background-color 0.2s;
}

.context-menu-item:hover {
  background: #404040;
  color: #ffffff;
}

.context-menu-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9998;
}

/* Element Plus 样式覆盖 */
:deep(.el-tabs) {
  height: 100%;
}

:deep(.el-tabs__header) {
  margin: 0;
  background: #2d2d2d;
  border-bottom: 1px solid #404040;
}

:deep(.el-tabs__nav) {
  border: none;
}

:deep(.el-tabs__item) {
  color: #cccccc;
  border: none;
  background: transparent;
}

:deep(.el-tabs__item.is-active) {
  color: #409eff;
  background: #363636;
}

:deep(.el-tabs__content) {
  height: calc(100% - 40px);
  padding: 0;
}

:deep(.el-tab-pane) {
  height: 100%;
}

:deep(.el-empty) {
  background: transparent;
}

:deep(.el-empty__description) {
  color: #cccccc;
}
</style>